package com.dingwen.treasure.open.api.pub.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.http.HttpUtil;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.dingwen.treasure.open.api.pub.bo.YueBo;
import com.dingwen.treasure.open.api.pub.config.WechatPubConfig;
import com.dingwen.treasure.open.api.pub.service.WechatPubService;
import com.google.common.collect.ImmutableMap;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.util.Assert;

import javax.annotation.Resource;
import java.util.List;
import java.util.Map;

/**
 * 微信公众号服务impl
 *
 * @author dingwen
 * @date 2022/12/28
 */
@Service
@Slf4j
public class WechatPubServiceImpl implements WechatPubService {

    @Resource
    private WechatPubConfig wechatPubConfig;

    /**
     * 令牌 </br>
     * <p>优化项目： 可根据接口返回状态判断token是否过期，再进行请求，否则使用缓存token即可</p>
     * <p>优化项目：可重试次数</p>
     */
    private static String TOKEN;

    Integer retryCount = 1;

    @Override
    public String fetchToken() {

        Map<String, Object> requestTokenParamMap = ImmutableMap.<String, Object>builder()
                .put(GRANT_TYPE_KEY, wechatPubConfig.getGrantType())
                .put(APPID_KEY, wechatPubConfig.getAppid())
                .put(SECRET_KEY, wechatPubConfig.getSecret())
                .build();
        String result = HttpUtil.get(wechatPubConfig.getTokenRrl(), requestTokenParamMap);
        Assert.isTrue(StrUtil.isNotBlank(result) && JSONUtil.isJson(result), "获取token返回结果空或不是JSON");
        JSONObject obj = JSONUtil.parseObj(result);
        String token = obj.get(TOKEN_KEY, String.class);
        Assert.isTrue(StrUtil.isNotBlank(token), "微信公众号token获取异常");
        TOKEN = token;
        return token;
    }

    @Override
    public List<String> fetchOpenIds() {
        Map<String, Object> paramMap = ImmutableMap.<String, Object>builder()
                .put(TOKEN_KEY, TOKEN)
                .build();
        String result = HttpUtil.get(wechatPubConfig.getOpenIdsUrl(), paramMap);
        Assert.isTrue(StrUtil.isNotBlank(result) && JSONUtil.isJson(result), "获取公众号关注用户列表返回结果空或不是JSON");
        JSONObject re = JSONUtil.parseObj(result);
        Integer code = re.get(ERR_CODE_KEY, Integer.class);
        if (ObjectUtil.isNotNull(code) && TOKEN_EXPIRED_CODE.equals(code)
                && retryCount <= wechatPubConfig.getRetryCount()) {
            log.info("token已经过期正在获取新token");
            retryCount++;
            fetchToken();
            fetchOpenIds();

        }
        JSONObject data = re.get(DATA_KEY, JSONObject.class);
        Assert.notNull(data, "获取公众号关注用户列表返回结果空");
        List<String> openIds = data.get(OPEN_IDS_KEY, List.class);
        Assert.isTrue(CollUtil.isNotEmpty(openIds), "未获取到openid");
        return openIds;
    }

    @Override
    public boolean pushTemplateMsgForYue(YueBo yueBo) {
        String url = wechatPubConfig.getPushTemplateMsgUrl().concat("?")
                .concat(TOKEN_KEY)
                .concat("=")
                .concat(TOKEN);
        String result = HttpUtil.createPost(url)
                .body(JSONUtil.toJsonStr(yueBo))
                .execute()
                .body();
        Assert.isTrue(StrUtil.isNotBlank(result) && JSONUtil.isJson(result), "推送模版消息异常，返回结果空或不是JSON");
        Integer code = JSONUtil.parseObj(result)
                .get(ERR_CODE_KEY, Integer.class);
        Assert.notNull(code, "接口返回校验码获取异常");
        if (TOKEN_EXPIRED_CODE.equals(code) && retryCount <= wechatPubConfig.getRetryCount()) {
            log.info("推送模版消息，token已经过期正在获取新token重试");
            retryCount++;
            fetchToken();
            pushTemplateMsgForYue(yueBo);

        }
        return true;
    }
}
